
local h485 ={}

local h485_cfg = {
    uid = 3,
    baud=115200,
    data=8,
    stop=1,
    parity=uart.NONE,
}
local volts, adcval = {}, {}
local usb_in_get, usb_lval = gpio.setup(29,nil), 0


local h485_data = {
    rbuff = {},
    rbuff_len = 0,
    strbuff = "",
}
local function update_sys_hconfig()
    hconfig.NET = fskv.get("NET") or hconfig.NET
    hconfig.DEV_NUMBER = fskv.get("DEV_NUMBER") or hconfig.DEV_NUMBER
    hconfig.COMPANY = fskv.get("COMPANY") or hconfig.COMPANY
    hconfig.HPROJECT = fskv.get("HPROJECT") or hconfig.HPROJECT
    hconfig.IMEI = fskv.get("IMEI") or hconfig.IMEI
    hconfig.SVERSION = fskv.get("SVERSION") or hconfig.SVERSION
    hconfig.MODI_DATA = fskv.get("MODI_DATA") or hconfig.MODI_DATA
    hconfig.ADC_A = fskv.get("ADC_A") or hconfig.ADC_A
    hconfig.ADC_B = fskv.get("ADC_B") or hconfig.ADC_B
    hconfig.LED_MODE = fskv.get("LED_MODE") or hconfig.LED_MODE
    hconfig.RESTART_FLAG = fskv.get("RESTART_FLAG") or hconfig.RESTART_FLAG
    hconfig.RESTART_HOUR = fskv.get("RESTART_HOUR") or hconfig.RESTART_HOUR
    hconfig.POWER_DATE = fskv.get("POWER_DATE") or hconfig.POWER_DATE
    hconfig.LAN_MODE = fskv.get("LAN_MODE") or hconfig.LAN_MODE
    hconfig.STA_4G = fskv.get("STA_4G") or hconfig.STA_4G
    hconfig.STA_SSID = fskv.get("STA_SSID") or hconfig.STA_SSID
    hconfig.STA_PSWD = fskv.get("STA_PSWD") or hconfig.STA_PSWD
end

h485.Sensor_val = {
    vol = 0,       --电压
    latitude = 0,  --纬度
    longitude = 0, --经度
    fack_flag = 0, --处理结果
    rs232_flag = 0, --232状态
    rs232_flag_recheck = 0, --232巡检状态
    usb_flag = 0,  --usb状态
    lan_flag = 0,  --lan状态
    sd_flag = 0,   --SD卡挂载状态
    sd_free = 0,   --SD卡剩余空间
    gps_flag = 0,  --0:未定位 1:gps 2:基站
    csq = { 0, 0 }, --网络类型 信号强度
    iccid = "",
    sim_sta = 0,   --SIM卡状态
    pow_work = 0,  --电源模式
    pow_flag = 1,  --负载状态
    recv_send_flag = 0,
    sta_4g_flag = 0, --4G和wifi工作状态,1为4G,2为wifi,0为未连接
}
function h485.write(s)
    -- log.info("uart1 write",s:toHex())
    uart.write(h485_cfg.uid, s)
end



function h485.init_sys_param()
    fskv.init()
    -- tf.tf_init()
    hconfig.param_init()
    -- hgps.gps_init()
    update_sys_hconfig()
end

-- 打印系统参数
function h485.print_hconfig_net()
    local buff = {}
    local str = ""
    update_sys_hconfig()
    local tClock = os.date("*t")
    buff[1] = utf8ToGb2312(string.format("##QN=%04d%02d%02d%02d%02d%02d;", tClock.year,
        tClock.month, tClock.day, tClock.hour, tClock.min,
        tClock.sec))
    buff[2] = utf8ToGb2312(string.format("MN=%s;IMEI=%s;ICCID=%s;", hconfig.DEV_NUMBER, hconfig.IMEI, h485.Sensor_val.iccid))
    for i = 1, #hconfig.NET.ser do
        str = str .. string.format("S%d=%s,%s,%d;", i, hconfig.NET.ser[i][1], hconfig.NET.ser[i][2], hconfig.NET.ser[i][3])
    end
    buff[3] = str
    buff[4] = utf8ToGb2312(string.format("REG=%d,%s;", hconfig.NET.reg[1], hconfig.NET.reg[2]))
    buff[5] = utf8ToGb2312(string.format("HEART=%d,%s;CSQ=%d,%d;", hconfig.NET.heart[1], hconfig.NET.heart[2], h485.Sensor_val.csq[1],
        h485.Sensor_val.csq[2]))
    buff[6] = utf8ToGb2312(string.format("CONPANY=%s;HPROJECT=%s;GPS=%d;SD=%d;", hconfig.COMPANY,
        hconfig.HPROJECT, h485.Sensor_val.gps_flag, h485.Sensor_val.sd_flag))
    buff[7] = utf8ToGb2312(string.format("ADC_A=%.2f,ADC_B=%.2f,VERSION=%s;\r\n", hconfig.ADC_A,
        hconfig.ADC_B, _G.VERSION))
    str = table.concat(buff)
    return str
end

-- 本地打印系统配置表
function h485.print_hconfig_local(num)
    local buff = {}
    update_sys_hconfig()
    local tClock = os.date("*t")
    local str = ""
    buff[1] = utf8ToGb2312("*******************系统配置表*******************\n")
    buff[2] = utf8ToGb2312(string.format("当前时间:%04d-%02d-%02d %02d:%02d:%02d\n", tClock.year, tClock.month, tClock.day,tClock.hour, tClock.min, tClock.sec))
    buff[3] = utf8ToGb2312(string.format("公司/项目名称：%s\n", hconfig.COMPANY))
    buff[4] = utf8ToGb2312(string.format("设备编号：%s\n", hconfig.DEV_NUMBER))
    str = ""
    for i = 1, #hconfig.NET.ser do
        str = str .. utf8ToGb2312(string.format("SOCKET%c#%d:%s,%s\n", 0x40+i, hconfig.NET.ser[i][3], hconfig.NET.ser[i][1], hconfig.NET.ser[i][2]))
    end
    buff[5] = str
    buff[6] = utf8ToGb2312(string.format("设备状态:RS232=%d,RS485=%d,4G信号=%d,%d,GPS天线=%d,经度=%.3f,纬度=%.3f\n", h485.Sensor_val.rs232_flag,
        h485.Sensor_val.usb_flag, h485.Sensor_val.csq[1], h485.Sensor_val.csq[2], h485.Sensor_val.gps_flag, h485.Sensor_val.longitude,
        h485.Sensor_val.latitude))
    buff[7] = utf8ToGb2312(string.format("卡片状态:SIM=%d,TF=%d\n", h485.Sensor_val.sim_sta, h485.Sensor_val.sd_flag))
    buff[8] = utf8ToGb2312(string.format("流量卡号ICCID:%s\n", h485.Sensor_val.iccid))
    buff[9] = utf8ToGb2312(string.format("设备IMEI:%s\n", hconfig.IMEI))
    buff[10] = utf8ToGb2312(string.format("注册包:%s,%s\n", hconfig.NET.reg[1], hconfig.NET.reg[2]))
    buff[11] = utf8ToGb2312(string.format("心跳包:%s,%s\n", hconfig.NET.heart[1], hconfig.NET.heart[2]))
    buff[12] = utf8ToGb2312(string.format("程序版本:%s\n", _G.VERSION))
    buff[13] = utf8ToGb2312(string.format("上次断电时间:%s\n", hconfig.POWER_DATE))
    buff[14] = utf8ToGb2312(string.format("*******************系统配置表*******************\n"))
    str = table.concat(buff)
    return str
end


-- 通讯配置恢复出厂
local function restore_socket()
    hconfig.NET = {
        ser = { { "120.78.210.171", "9666", 1 },
            { "119.23.134.117", "9450", 1 },
            { "",               "",     0 },
            { "",               "",     0 }, },
        reg = { 0, "" },
        heart = { 0, "" }
    }
    fskv.set("NET", hconfig.NET)
    update_sys_hconfig()
    pm.reboot("NET restore reset.")
end

-- 配置项目名称
local function update_hproject(data)
    local str = string.format("%s", data)
    fskv.set("HPROJECT", str)
    update_sys_hconfig()
end
-- 配置设备编号
local function update_hdev_number(data)
    local str = string.format("%s", data)
    str = string.gsub(str, "%z", "")
    fskv.set("DEV_NUMBER", str)
    update_sys_hconfig()
end

local function update_sta_4g(data)
    if data == 1 then
        hconfig.STA_4G = 1
    else
        hconfig.STA_4G = 0
    end
    fskv.set("STA_4G", hconfig.STA_4G)
end

-- 服务器地址更新
local function update_net(num, data)
    local ip, flag,lastflag
    local len = #data
    lastflag = hconfig.NET.ser[num][3]
    flag = data:byte(1)
    ip = data:sub(2, len - 2)
    local _, port = pack.unpack(data, ">H", len - 1)
    port = string.format("%d", port)
    hconfig.NET.ser[num] = { ip, port, flag }
    fskv.sett("NET", "ser", hconfig.NET.ser)
    hsocket.dtu.ClientCloseFlag[num] = 1
    if lastflag~=flag then
        log.info("NET restore reset.")
        pm.reboot()
    end
    log.info("NET cg:", ip, port)
end

local function update_net_sta(data)
    if #data >= 4 then
        for i = 1, 4 do
            hconfig.NET.ser[i][3] = data:byte(i)
            if hconfig.NET.ser[i][3] > 3 then
                hconfig.NET.ser[i][3] = 1
            end
        end
        fskv.sett("NET", "ser", hconfig.NET.ser)
        hsocket.dtu.ClientCloseFlag = { 1, 1, 1, 1 }
        sys.timerStart(pm.reboot, 3000, "NET restore reset.")
    end
end

--获取ICCID
function h485.update_iccid()
    if hsocket.is_ready() then
        --获取sim卡iccid
        -- ril.request("AT+ICCID")
        local iccid = mobile.iccid()
        if iccid ~= nil then
            h485.Sensor_val.iccid = iccid
        end
    end
end
--获取SIM卡状态
function h485.update_sim()
    if mobile.simPin(0) then
        h485.Sensor_val.sim_sta = 1
    else
        h485.Sensor_val.sim_sta = 0
    end
end
--获取信号模式、强度
function h485.update_csq()
    h485.Sensor_val.csq[1] = mobile.status()
    h485.Sensor_val.csq[2] = mobile.csq()
end

--获取IMEI
function h485.update_imei()
    local imei = mobile.imei()
    if imei ~= "" and imei ~= nil then
        hconfig.IMEI = imei
        fskv.set("IMEI", hconfig.IMEI)
    end
end

--更新注册包
local function update_net_reg(data)
    local flag = data:byte(1)
    if #data < 50 and flag < 0x02 then
        hconfig.NET.reg[1] = flag
        hconfig.NET.reg[2] = data:sub(2, #data - 1)
        fskv.sett("NET", "reg", hconfig.NET.reg)
        hsocket.dtu.ClientCloseFlag = { 1, 1, 1, 1 }
    end
end

--更新心跳包
local function update_net_heart(data)
    local flag = data:byte(1)
    if #data < 50 and flag < 0x02 then
        hconfig.NET.heart[1] = flag
        hconfig.NET.heart[2] = data:sub(2, #data-1)
        fskv.sett("NET", "heart", hconfig.NET.heart)
    end
end
--ADC电压校准
local function adc_volts_check(data)
    if data:byte(1) == 0xD1 then
        volts[1] = tonumber(data:sub(2, #data), 10)
        adcval[1], _ = hadc.adc0_read()
        log.info("vol,adcval:", volts[1], adcval[1])
    elseif data:byte(1) == 0xD2 then
        volts[2] = tonumber(data:sub(2, #data), 10)
        adcval[2], _ = hadc.adc0_read()
        hadc.hadc_Check(adcval[1], volts[1], adcval[2], volts[2])
        log.info("vol,adcval:", volts[2], adcval[2])
    end
end

local function update_rs232_flag(msg)
    if msg == gpio.RISING then
        log.info("[RS232]->UP.")
        h485.Sensor_val.rs232_flag = 1
        h485.Sensor_val.rs232_flag_recheck = 1
    end
end
local rs232_in_get = gpio.setup(30,update_rs232_flag,gpio.PULLDOWN)

local function time_check()
    local tClock = os.date("*t")
    if tClock.year == 2000 and tClock.month == 1 then
        tClock.year = 2022
        tClock.month = 9
        tClock.day = 26
        tClock.hour = 8
        misc.setClock(tClock)
        log.info("Datetime sync fail,restored.")
    end
end

local function update_time(data)
    local tClock = os.date("*t")
    if #data >= 6 then
        tClock.year = data:byte(1) + 0x7D0
        tClock.month = data:byte(2)
        tClock.day = data:byte(3)
        tClock.hour = data:byte(4)
        tClock.min = data:byte(5)
        tClock.sec = data:byte(6)
        rtc.set({year=tClock.year,mon=tClock.month,day=tClock.day,hour= tClock.hour,min=tClock.min,sec=tClock.sec})
        hsocket.printTime()
    end
end

local function update_peri_status()
    h485.Sensor_val.usb_flag = usb_in_get()
    -- log.info("h485.Sensor_val.usb=",usb_in_get(),"\n")
    -- log.info("h485.Sensor_val.rs232_flag=",h485.Sensor_val.rs232_flag,"\n")
    h485.Sensor_val.vol = hadc.volts_read()
    if (h485.Sensor_val.usb_flag == 1) and (usb_lval == 0) then
        log.info("[485]->切换usb输入.")
        uart.setup(h485_cfg.uid, 115200, 8, uart.PAR_NONE, uart.STOP_1)
        usb_lval = 1
    elseif (h485.Sensor_val.usb_flag == 0) and (usb_lval == 1) then
        log.info("[USB]->切换485输入.")
        uart.setup(h485_cfg.uid, h485_cfg.baud, 8, uart.PAR_NONE, uart.STOP_1)
        usb_lval = 0
    end
    if h485.Sensor_val.vol == 0 then
        local tClock=os.date("%c")
        log.info("[sys]->系统断电:",tClock)
        hconfig.POWER_DATE=tClock
        fskv.set("POWER_DATE", hconfig.POWER_DATE)
        tf.tf_write_data("[sys]->power down.","")
    end
    
end

--[[
-- 串口数据解析
F0 04 BF 系统参数
F2 项目名配置
F3 设备号配置
F4 本地校时
F5 07 7F 实时数据
F7 C6 FE 通讯配置
FA 03 3F 系统复位
FB GPS校时
FC 继电器
-------返回值0：透传|1：命令且返回|2：
]]
function h485.cmd_parse(data)
    local ret = 0
    local dev
    -- 大端序列
    local cmd = pack.pack('>h', crypto.crc16("MODBUS", data:sub(1, #data - 2)))
    -- 小端序列
    local sensor = pack.pack('<h',
        crypto.crc16("MODBUS", data:sub(1, #data - 2)))
    if cmd == data:sub(#data - 1, #data) then
        log.debug("incoming cmd parse.")
        ret = 1
        -- 系统参数
        dev = data:byte(1)
        if 0xF0 == dev then
            -- print_sys_hconfig()
        elseif 0xF2 == dev then
            update_hproject(data:sub(2, #data - 2))
        elseif 0xF3 == dev then
            update_hdev_number(data:sub(2, #data - 2))
        elseif 0xF4 == dev then
            update_time(data:sub(2, #data - 2))
        elseif 0xF5 == dev then
        elseif 0xF6 == dev then
        elseif 0xF7 == dev then
            restore_socket()
        elseif 0xF8 == dev then
            h485.update_iccid()
        elseif 0xF9 == dev then
        elseif 0xFA == dev then
            pm.reboot('soft restart')
            -- elseif 0xFC == dev then
            -- update_ctrl(data:sub(2, #data - 2))
        elseif 0xFB == dev then
            -- sensor_check_madjust(data:sub(2, #data - 2))
        elseif 0xFC == dev then
        elseif 0xD1 == dev then
            update_net(1, data:sub(2, #data - 2))
        elseif 0xD2 == dev then
            update_net(2, data:sub(2, #data - 2))
        elseif 0xD3 == dev then
            update_net(3, data:sub(2, #data - 2))
        elseif 0xD4 == dev then
            update_net(4, data:sub(2, #data - 2))
        elseif 0xD5 == dev then
            update_net_heart(data:sub(2, #data - 2))
        elseif 0xD6 == dev then
            update_net_reg(data:sub(2, #data - 2))
        elseif 0xD7 == dev then
            update_net_sta(data:sub(2, #data - 2))
        elseif 0xDD == dev then
            adc_volts_check(data:sub(2, #data - 2))
        end
        if dev >= 0xF0 and dev <= 0xF7 then
            log.info(h485.print_hconfig_local())
        end
    elseif "##" == data:sub(1, 2) then
        log.debug("incoming HJ212 data.")
    end
    return ret
end

-- ----------------------------串口驱动---------------------------------

-- 注册串口的数据发送通知函数
uart.on(h485_cfg.uid, "receive", function(id, len)
    local s = ""
    repeat
        s = uart.read(id)
        if #s > 0 then -- #s 是取字符串的长度
            -- 关于收发hex值,请查阅 https://doc.openluat.com/article/583
            log.info("uart", "receive", id, #s, s)
            table.insert(h485_data.rbuff, s)
            h485_data.rbuff_len = h485_data.rbuff_len + #s
            if h485_data.rbuff_len > 29200 then
                h485_data.rbuff = {}
                h485_data.rbuff_len = 0
            end
        end
    until s == ""
end)


-- -- 配置并且打开串口
uart.setup(h485_cfg.uid, h485_cfg.baud, 8, uart.STOP_1, uart.PAR_NONE)

-- 启动串口数据接收任务
sys.taskInit(function()
    local tmp, cnt = 0, 0
    while true do
        sys.wait(1000)
        cnt = cnt + 1
        update_peri_status()
        -- wdt.feed()
        if cnt % 20 == 0 then
            h485.update_sim()
            h485.update_csq()
            if hconfig.IMEI == "" then
                h485.update_imei()
            end
            collectgarbage("collect")
            log.info("打印占用的内存:", rtos.meminfo()) -- 打印占用的RAM
            log.info("打印可用的空间", rtos.meminfo('sys')) -- 打印剩余FALSH，单位Byte
        end
        if cnt % 30 == 0 then
            hsocket.hdev_status_pack()
            -- if h485.Sensor_val.sd_flag == 0 and cnt % 300 == 0 then
            --     tf.tf_init()
            -- end
            if cnt % 60 == 0 then
                if rs232_in_get() == 1 then
                    h485.Sensor_val.rs232_flag = 1
                    h485.Sensor_val.rs232_flag_recheck = 1
                elseif h485.Sensor_val.rs232_flag == 1 and h485.Sensor_val.rs232_flag_recheck == 1 then
                    if cnt % 14400 == 0 then
                        h485.Sensor_val.rs232_flag_recheck = 0
                    end
                elseif h485.Sensor_val.rs232_flag == 1 and h485.Sensor_val.rs232_flag_recheck == 0 then
                    h485.Sensor_val.rs232_flag = 0
                end
            end
            local tClock = os.date("*t")
            if tClock.hour==23 and tClock.min==59 and tClock.day % 5 == 0 then
                sys.timerStart(pm.reboot, 30, "Server timer restart")
            end
        end
        if cnt > 999999 then
            cnt = 0
        end
    end
end)

sys.taskInit(function()
    local send_buff = ""
    while true do
        if h485_data.rbuff_len > 0 then
            h485_data.strbuff = table.concat(h485_data.rbuff)
            h485_data.rbuff = {}
            h485_data.rbuff_len = 0
            if h485.cmd_parse(h485_data.strbuff) == 0 then
                send_buff = rs232.serial2dtu(h485_data.strbuff)
                if send_buff ~= "" then
                    -- log.debug("send buff:",#send_buff,string.toHex(send_buff))
                    -- tf.tf_write_data("[u485]",send_buff)
                    hsocket.hsocket_send(send_buff, 0, 1)
                    send_buff = ""
                end
            else
                h485.write(h485.print_hconfig_local())
            end
        end
        sys.wait(1000)
    end
end)

return h485
